home *** CD-ROM | disk | FTP | other *** search
- We will now discuss in a little more detail
- the struggle for existence.
- Charles Darwin
-
- SoftICE Tutorial
-
- Introduction
- Loading SoftICE
- Building the GDIDEMO Sample Application
- Loading the GDIDEMO Sample Application
- Controlling the SoftICE Screen
- Tracing and Stepping through Source Code
- Viewing Local Data
- Setting Point-and-Shoot Breakpoints
- Setting a One-Shot Breakpoint
- Setting a Sticky Breakpoint
- Using SoftICE Informational Commands
- Using Symbols and Symbol Tables
- Setting a Conditional Breakpoint
- Setting a BPX Breakpoint
- Editing a Breakpoint
- Setting a Read-Write Memory Breakpoint
-
- Introduction
-
- This tutorial gives you hands-on experience debugging a Windows
- application to teach you the fundamental steps for debugging
- applications and drivers. During this debugging session, you will
- learn how to do the following:
-
- * Load SoftICE
- * Build an application
- * Load the application source and symbol files
- * Trace and step through source code and assembly language
- * View local data and structures
- * Set point-and-shoot breakpoints
- * Use SoftICE informational commands to explore the state of the
- application
- * Work with symbols and symbol tables
- * Modify a breakpoint to use a conditional expression
-
- Each section in the tutorial builds upon the previous sections, so you
- should perform them in order.
-
- This tutorial uses the GDIDEMO application as its basis. GDIDEMO
- provides a demonstration of GDI functionality. GDIDEMO is located in
- the \EXAMPLES\GDIDEMO directory on your CDROM. GDIDEMO is also
- available under \mstools\samples\win32\GDIDEMO. If you use the GDIDEMO
- on the CDROM, copy it to your hard drive.
-
- You can substitute a different sample application or an application of
- your own design. The debugging principles and features of SoftICE used
- in this tutorial apply to most applications.
-
- Note: The examples is this tutorial are based on Windows NT. If you
- are using Windows 95, your output may vary slightly.
-
- Loading SoftICE
-
- If you are running SoftICE under Windows 95 or under Windows NT in
- Boot, System, or Automatic mode, SoftICE automatically loads when you
- start or reboot your PC. If you are running SoftICE in Manual Startup
- mode under Windows NT, SoftICE does not load automatically.
-
- To load SoftICE for Windows 95, enter the command WINICE. To load
- SoftICE for Windows NT, do one of the following:
-
- * Select START SOFTICE.
- * Enter the command: NET START NTICE
-
- Note: Once you load SoftICE, you cannot deactivate it until you reboot
- your PC.
-
- To verify that SoftICE is loaded, press the SoftICE hot key sequence
- Ctrl-D. The SoftICE screen should appear. To return to the Windows
- operating system, use the X (exit) or G (go to) command (F5).
-
- Building the GDIDEMO Sample Application
-
- The first step in preparing to debug a Windows application is to build
- it with debug information. The makefile for the sample application
- GDIDEMO is already set up for this purpose.
-
- To build the sample program, perform the following steps:
-
- 1. Open a DOS shell.
-
- 2. Change to the directory that contains the sample code.
-
- 3. Execute the NMAKE command:
-
- C:\MSTOOLS\SAMPLES\WIN32\GDIDEMO>NMAKE
-
- If GDIDEMO is located in another directory, change the path as
- appropriate.
-
- Loading the GDIDEMO Sample Application
-
- Loading an application entails creating a symbol file from the
- applicationÆs debug information and loading the symbol and source
- files into SoftICE. To Load the GDIDEMO application, perform the
- following steps:
-
- 1. Start Symbol Loader : The Symbol Loader window appears.
-
- 2. Either choose OPEN MODULE from the File menu or click the OPEN
- button : The Open window appears.
-
- 3. Locate GDIDEMO.EXE and click Open.
-
- 4. Either choose LOAD from the Module menu or click the LOAD button to
- load GDIDEMO.
-
- Symbol Loader translates the debug information into a .NMS symbol
- file, loads the symbol and source files, starts GDIDEMO, pops up the
- SoftICE screen, and displays the source code for the file GDIDEMO.C.
-
- Controlling the SoftICE Screen
-
- The SoftICE screen is your central location for viewing and debugging
- code. It provides up to seven windows and one help line to let you
- view and control various aspects of your debugging session. By
- default, it displays the following:
-
- Locals window: Displays and expand variables allocated on the stack.
-
- Code window: Displays source code or unassembled instructions.
-
- Command window: Enters user commands and display information.
-
- Help line: Provides information about SoftICE commands and shows the
- active address context.
-
- 1. Look at the contents of the Code window. Note that SoftICE is
- displaying the WinMain routine at line 34. By default, SoftICE creates
- a breakpoint and stops at the first main module it encounters when
- loading your application.
-
- 2. To see all the source files that SoftICE loaded, enter the FILE
- command with the wild card character:
-
- :FILE *
-
- SoftICE displays the source files for GDIDEMO: draw.c, maze.c,
- xform.c, poly.c, wininfo.c, dialog.c, init.c, bounce.c, and gdidemo.c.
- The Command window varies in size depending upon the number of lines
- used by open windows, so you might not see all these file names. To
- display the remaining file names, press any key. (Refer to Chapter 5:
- Navigating Through SoftICE on page 69 for information about resizing
- windows.)
-
- 3. Many SoftICE windows can be scrolled. If you have a mouse, you can
- click on the scroll arrows. If not, SoftICE provides key sequences
- that let you scroll specific windows. Try these methods for scrolling
- the Code window:
-
- Scroll the Code Window Key Sequence Mouse Action
-
- Scroll to the previous Click the innermost up
- page. PageUp scroll arrow
-
- Scroll to the next Click the innermost down
- page. PageDown scroll arrow
-
- Scroll to the previous Click the outermost up
- line. UpArrow scroll arrow
-
- Scroll to the next Click the outermost down
- line. DownArrow scroll arrow
-
- Scroll left one Click the left scroll
- character. Ctrl-LeftArrow arrow
-
- Scroll right one Click the right scroll
- character. Ctrl-RightArrow arrow
-
- 4. Enter the U command followed by EIP to disassemble the instructions
- for the current instruction pointer.
-
- :U EIP
-
- You can also use the . (dot) command to accomplish the same thing:
-
- :.
-
- Tracing and Stepping through Source Code
-
- The following steps show you how to use SoftICE to trace through
- source code:
-
- 1. Enter the T (trace) command or press the F8 key to trace one
- instruction.
-
- :T
-
- The F8 key is the default key for the T (trace) command.
-
- Execution proceeds to the next source line and highlights it. At this
- point, the following source line should be highlighted:
-
- if(!hPrevInst)
-
- 2. The Code window is currently displaying source code. However, it
- can also display disassembled code or mixed (both source and
- disassembled) code. To view mixed code, use the SRC command (F3).
-
- :SRC
-
- Note that each source line is followed by its assembler instructions.
-
- 3. Press F3 once to see disassembled code, then again to return to
- source code.
-
- 4. Enter the T command (F8) to trace one instruction. Execution
- proceeds until it reaches the line that executes the RegisterAppClass
- function.
-
- As demonstrated in these steps, the T command executes one source
- statement or assembly language instruction. You can also use the P
- command (F10) to execute one program step. Stepping differs from
- tracing in one crucial way. If you are stepping and the statement or
- instruction is a function call, control is not returned until the
- function call is complete.
-
- Hint: The T command does not trace into a function call if the source
- code is not available. A good example of this is Win32 API calls. To
- trace into a function call when source code is not available, use the
- SRC command (F3) to switch into mixed or assembly mode.
-
- Viewing Local Data
-
- The Locals window displays the current stack frame. In this case, it
- contains the local data for the WinMain function. The following steps
- illustrate how to use the Locals window:
-
- 1. Enter the T command to enter the RegisterAppClass function. The
- Locals window is now empty because local data is not yet allocated for
- the function.
-
- The RegisterAppClass function is implemented in the source file
- INIT.C. SoftICE displays the current source file in the upper left
- corner of the Code window.
-
- 2. Enter the T command again. The Locals window contains the parameter
- passed to the RegisterAppClass (hInstance) and a local structure
- wndClass. The structure tag wndClass is marked with a plus sign (+).
- This plus sign indicates that you can expand the structure to view its
- contents.
-
- Note: You can also expand character strings and arrays.
-
- 3. If you have a Pentium-class processor and a mouse, double-click the
- structure WNDCLASSA to expand it. To collapse the structure wndClass,
- double-click its contents.
-
- 4. To use the keyboard to expand the structure: press Alt-L to move
- the cursor to the Locals window, use the UpArrow or DownArrow to move
- the highlight bar to the structure, and press Enter. Press Enter again
- to collapse it.
-
- Setting Point-and-Shoot Breakpoints
-
- This section shows you how to set two handy types of point-and-shoot
- breakpoints: one-shot and sticky breakpoints.
-
- Setting a One-Shot Breakpoint
-
- The following steps demonstrate how to set a one-shot breakpoint. A
- one-shot breakpoint clears after the breakpoint is triggered.
-
- 1. To shift focus to the Code window, either use your mouse to click
- in the window or press Alt-C.
-
- If you wanted to shift focus back to the Command window you could
- press Alt-C again. Setting Point-and-Shoot Breakpoints
-
- 2. Either use the Down arrow key, the down scroll arrow, or the U
- command to place the cursor on line 61, the first call to the Win32
- API function RegisterClass. If you use the U command, specify the
- source line 61 as follows:
-
- :U .61
-
- SoftICE places source line 61 at the top of the Code window.
-
- 3. Use the HERE command (F7) to execute to line 61. The HERE command
- executes from the current instruction to the instruction that contains
- the cursor. The HERE command sets a one-shot breakpoint on the
- specified address or source line and continues execution until that
- breakpoint triggers. When the breakpoint is triggered, SoftICE
- automatically clears the breakpoint so that it does not trigger again.
-
- The following current source line should be highlighted:
-
- if(!RegisterClass(&wndClass))
-
- Note: You can do the same thing by using the G (go) command and
- specifying the line number or address to which to execute:
-
- :G .61
-
- Setting a Sticky Breakpoint
-
- The following steps demonstrate another type of point-and-shoot
- breakpoint: the sticky breakpoint, which does not clear until you
- explicitly clear it.
-
- The F9 key is the default key for the BPX command.
-
- 1. Find the next call to RegisterClass that appears on source line 74.
- With the cursor on line 74, enter the BPX command (F9) to set an
- execution breakpoint. The BPX command sets an execution breakpoint by
- inserting an INT3 instruction into the code. Note that the line is
- highlighted when you set a breakpoint.
-
- 2. Press the F9 key to clear the breakpoint. If you are using a
- Pentium-class processor and you have a mouse, you can double-click on
- a line in the Code window to set or clear a breakpoint.
-
- 3. Set a breakpoint on line 74, then use the G or X command (F5) to
- execute the instructions until the breakpoint triggers:
-
- :G
-
- When the INT3 instruction is executed, SoftICE pops up. Unlike the
- HERE command, which sets a one-shot breakpoint, the BPX command sets a
- sticky breakpoint. A sticky breakpoint remains until you clear it.
-
- 4. To view information about breakpoints that are currently set, use
- the BL command:
-
- :BL
- 00) BPX #0137:00402442
-
- Note: The address you see might be different.
-
- From the output of the BL command, one breakpoint is set on code
- address 0x402442. This address equates to source line 74 in the
- current file INIT.C.
-
- 5. You can use the SoftICE expression evaluator to translate a line
- number into an address. To find the address for line 74, use the ?
- command:
-
- :? .74
- void * = 0x00402442
-
- 6. The RegisterAppClass function has a relatively straightforward
- implementation, so it is unnecessary to trace every single source
- line. Use the P command with the RET parameter (F12) to return to the
- point where this function was called:
-
- :P RET
-
- The RET parameter to the P command causes SoftICE to execute
- instructions until the function call returns. Because RegisterAppClass
- was called from within WinMain, SoftICE pops up in WinMain on the
- statement after the RegisterAppClass function call.
-
- The following source line in WinMain should be highlighted:
-
- msg.wParam = 1;
-
- 7. Enter the BC command with the wild card parameter to clear all the
- breakpoints:
-
- BC *
-
- Using SoftICE Informational Commands
-
- SoftICE provides a wide variety of informational commands that detail
- the state of an application or the system. This section teaches you
- about two of them: H (help) and CLASS.
-
- 1. The H and Class commands work best when you have more room to
- display information, so use the WL command to close the Locals window.
- Closing this window automatically increases the size of the Command
- window.
-
- 2. The H command provides general help on all the SoftICE commands or
- detailed help on a specific command. To view detailed help about the
- CLASS command, enter CLASS as the parameter to the H command.
-
- :H CLASS
- Display window class information
- CLASS [-x] [process | thread | module | class-name]
- ex: CLASS USER
-
- The first line of help provides a description of the command. The
- second line is the detailed use, including any options and/or
- parameters the command accepts. The third line is an example of the
- command.
-
- 3. The purpose of the RegisterAppClass function is to register window
- class templates that are used by the GDIDEMO application to create
- windows. Use the CLASS command to examine the classes registered by
- GDIDEMO.
-
- :CLASS GDIDEMO
-
- Note: This example shows only those classes specifically registered by
- the GDIDEMO application. Classes registered by other Windows modules,
- such as USER32, are omitted.
-
- The output of the CLASS command provides summary information for each
- window class registered on behalf of the GDIDEMO process. This
- includes the class name, the address of the internal WINCLASS data
- structure, the module which registered the class, the address of the
- default window procedure for the class, and the value of the class
- style flags.
-
- Note: For more specific information on window class definitions, use
- the CLASS command with the -X option, as follows:
-
- :CLASS -X
- Class Name Handle Owner WndwProc Styles
- ---------------Application Private---------------
- BOUNCEDEMO A018A3B0 GDIDEMO 004015A4 00000003
- DRAWDEMO A018A318 GDIDEMO 00403CE4 00000003
- MAZEDEMO A018A280 GDIDEMO 00403A94 00000003
- XFORMDEMO A018A1E8 GDIDEMO 00403764 00000003
- POLYDEMO A018A150 GDIDEMO 00402F34 00000003
- GDIDEMO A018A0C0 GDIDEMO 004010B5 00000003
-
- Using Symbols and Symbol Tables
-
- Now that you are familiar with using SoftICE to step, trace, and
- create point-and-shoot style breakpoints, it is time to explore
- symbols and tables. When you load symbols for an application, SoftICE
- creates a symbol table that contains all the symbols defined for that
- module.
-
- 1. Use the TABLE command to see all the symbol tables that are loaded:
-
- :TABLE
- GDIDEMO [NM32]
- 964657 Bytes Of Symbol Memory Available
-
- The currently active symbol table is listed in bold. This is the
- symbol table used to resolve symbol names. If the current table is not
- the table from which you want to reference symbols, use the TABLE
- command and specify the name of the table to make active:
-
- :TABLE GDIDEMO
-
- 2. Use the SYM command to display the symbols from the current symbol
- table. With the current table set to GDIDEMO, the SYM command produces
- output similar to the following abbreviated output:
-
- :SYM
- .text(001B)
- 001B:00401000 WinMain
- 001B:004010B5 WndProc
- 001B:004011DB CreateProc
- 001B:00401270 CommandProc
- 001B:00401496 PaintProc
- 001B:004014D2 DestroyProc
- 001B:004014EA lRandom
- 001B:00401530 CreateBounceWindow
- 001B:004015A4 BounceProc
- 001B:004016A6 BounceCreateProc
- 001B:00401787 BounceCommandProc
- 001B:0040179C BouncePaintProc
-
- This list of symbol names is from the .text section of the executable.
- The .text section is typically used for procedures and functions. The
- symbols displayed in this example are all functions of GDIDEMO.
-
- Setting a Conditional Breakpoint
-
- One of the symbols defined for the GDIDEMO application is the
- LockWindowInfo function. The purpose of this routine is to retrieve a
- pointer value that is specific to a particular instance of a window.
- To learn about conditional and memory breakpoints, you will perform
- the following steps:
-
- * Set a BPX breakpoint on the LockWindowInfo function.
-
- * Edit the breakpoint to use a conditional expression, thus setting a
- conditional breakpoint.
-
- * Set a memory breakpoint to monitor access to a key piece of
- information, as described in Setting a Read-Write Memory Breakpoint on
- page 39.
-
- Setting a BPX Breakpoint
-
- Before setting the conditional breakpoint, you need to set a BPX-style
- breakpoint on LockWindowInfo.
-
- 1. Set a BPX-style breakpoint on the LockWindowInfo function:
-
- :BPX LockWindowInfo
-
- When one of the GDIDEMO windows needs to draw information in its
- client area, it calls the LockWindowInfo function. Every time the
- LockWindowInfo function is called, SoftICE pops up to let you debug
- the function. The GDIDEMO windows continually updates, so this
- breakpoint goes off quite frequently.
-
- 2. Use the BL command to verify that the breakpoint is set.
-
- 3. Use either the X or G command to exit SoftICE. SoftICE should pop
- up almost immediately on the LockWindowInfo function.
-
- Editing a Breakpoint
-
- From the LockWindowInfo function prototype on source line 47, you can
- see that the function accepts one parameter of type HWND and returns a
- void pointer type. The HWND parameter is the handle to the window that
- is attempting to draw information within its client area. At this
- point, you want to modify the existing breakpoint, adding a
- conditional breakpoint to isolate a specific HWND value.
-
- 1. Before you can set the conditional expression, you need to obtain
- the HWND value for the POLYDEMO window. The HWND command provides
- information about application windows. Use the HWND command and
- specify the GDIDEMO process:
-
- :HWND GDIDEMO
-
- The following example illustrates what you should see if you are using
- Windows NT. If you are using Windows 95, your output will vary.
-
- Handle Class WinProc TID Module
- 07019C GDIDEMO 004010B5 2D GDIDEMO
- 100160 MDIClient 77E7F2F5 2D GDIDEMO
- 09017E BOUNCEDEMO 004015A4 2D GDIDEMO
- 100172 POLYDEMO 00402F34 2D GDIDEMO
- 11015C DRAWDEMO 00403CE4 2D GDIDEMO
-
- The POLYDEMO window handle is bold and underlined. This is the window
- handle you want to use to form a conditional expression. If the
- POLYDEMO window does not appear in the HWND output, exit SoftICE using
- the G or X commands (F5) and repeat Step 1 until the window is
- created.
-
- The value used in this example is probably not the same value that
- appears in your output. For the exercise to work correctly, you must
- use the HWND command to obtain the actual HWND value on your system.
-
- Using the POLYDEMO window handle, you can set a conditional expression
- to monitor calls to LockWindowInfo looking for a matching handle
- value. When the LockWindowInfo function is called with the POLYDEMO
- window handle, SoftICE pops up.
-
- 2. Because you already have a breakpoint set on LockWindowInfo, use
- the BPE command (Breakpoint Edit) to modify the existing breakpoint:
-
- :BPE 0
-
- When you use the BPE command to modify an existing breakpoint, SoftICE
- places the definition of that breakpoint onto the command line so that
- it can be easily edited. The output of the BPE command appears:
-
- :BPX LockWindowInfo
-
- The cursor appears at the end of the command line and is ready for you
- to type in the conditional expression.
-
- 3. Remember to substitute the POLYDEMO window handle value that you
- found using the HWND command instead of the value (100172) used in
- this example. Your conditional expression should appear similar to the
- following example. The conditional expression appears in bold type.
-
- :BPX LockWindowInfo IF ESP->4 == 100172
-
- Note: Win32 applications pass parameters on the stack and at the entry
- point of a function; the first parameter has a positive offset of 4
- from the ESP register. Using the SoftICE expression evaluator, this is
- expressed in the following form: ESP->4. ESP is the CPU stack pointer
- register and the "->" operator causes the lefthand side of the
- expression (ESP) to be indirected at the offset specified on the
- righthand side of the expression (4). For more information on the
- SoftICE expression evaluator refer to Chapter 8: Using Expressions on
- page 125 and for referencing the stack in conditional expressions
- refer to Conditional Breakpoints on page 114.
-
- 4. Verify that the breakpoint and conditional expression are correctly
- set by using the BL command.
-
- 5. Exit SoftICE using the G or X command (F5).
-
- When SoftICE pops up, the conditional expression will be TRUE.
-
- Setting a Read-Write Memory Breakpoint
-
- We set the original breakpoint and subsequently the conditional
- expression so that we could obtain the address of a data structure
- specific to this instance of the POLYDEMO window. This value is stored
- in the windowÆs extra data and is a global handle. The LockWindowInfo
- function retrieves this global handle and uses the Win32 API LocalLock
- to translate it into a pointer that can be used to access the windowÆs
- instance data.
-
- 1. Obtain the pointer value for the windows instance data by executing
- up to the return statement on source line 57:
-
- :G .57
-
- 2. Win32 API functions return 32-bit values in the EAX register, so
- you can use the BPMD command and specify the EAX register to set a
- memory breakpoint on the instance data pointer.
-
- :BPMD EAX
-
- The BPMD command uses the hardware debug registers provided by Intel
- CPUs to monitor reads and writes to the Dword value at a linear
- address. In this case, you are using BPMD to trap read and write
- accesses to the first Dword of the window instance data.
-
- 3. Use the BL command to verify that the memory breakpoint is set.
- Your output should look similar to the following:
-
- :BL
- 00) BPX LockWindowInfo IF ((ESP->4)==0x100172)
- 01) BPMD #0023:001421F8 RW DR3
-
- Breakpoint index 0 is the execution breakpoint on LockWindowInfo and
- breakpoint index 1 is the BPMD on the window instance data.
-
- 4. Use the BD command to disable the breakpoint on the LockWindowInfo.
-
- :BD 0
-
- SoftICE provides the BC (breakpoint clear) and BD (breakpoint disable)
- commands to clear or disable a breakpoint. Disabling a breakpoint is
- useful if you want to re-enable the breakpoint later in your debugging
- session. If you are not interested in using the breakpoint again, then
- it makes more sense to clear it.
-
- 5. Use the BL command to verify that the breakpoint on LockWindowInfo
- is disabled. SoftICE indicates that a breakpoint is disabled by
- placing an asterisk (*) after the breakpoint index. Your output should
- appear similar to the following:
-
- :BL
- 00) * BPX _LockWindowInfo IF ((ESP->4)==0x100172)
- 01) BPMD #0023:001421F8 RW DR3
-
- Note: You can use the BE command to re-enable a breakpoint:
-
- :BE breakpoint-index-number
-
- 6. Exit SoftICE using the G or X command. When the POLYDEMO window
- accesses the first Dword of its window instance data, the breakpoint
- triggers and SoftICE pops up.
-
- When SoftICE pops up due to the memory breakpoint, you are in the
- PolyRedraw or PolyDrawBez function. Both functions access the
- nBezTotal field at offset 0 of the POLYDRAW window instance data.
-
- Note: The Intel CPU architecture defines memory breakpoints as traps,
- which means that the breakpoint triggers after the memory has been
- accessed. In SoftICE, the instruction or source line that is
- highlighted is the one after the instruction or source line that
- accessed the memory.
-
- 7. Clear the breakpoints you set in this section by using the BC
- command:
-
- :BC *
-
- Note: You can use the wildcard character (*) with the BC, BD, and BE
- commands to clear, disable, and enable all breakpoints.
-
- 8. Exit SoftICE using the G or X command.
-
- The operating system terminates the application.
-
- Congratulations on completing your first SoftICE debugging session. In
- this session, you traced through source code, viewed locals and
- structures, and set point-and-shoot, conditional, and read-write
- memory breakpoints. SoftICE provides many more advanced features. The
- SoftICE commands ADDR, HEAP, LOCALS, QUERY, THREAD, TYPES, WATCH, and
- WHAT are just a few of the many SoftICE commands that help you debug
- smarter and faster. Refer to the SoftICE Command Reference for a
- complete explanation of all the SoftICE commands.
-